
#include "stdafx.h"
#include "HRKNodeAnim.h"
#include "HRKMesh.h"
#include "HRKExport.h"

#define FORCE_EXPORT_TOPLEVEL_NODE_ANIMATION
//#define FORCE_EXPORT_BIP01_ANIMATION
//#define FORCE_EXPORT_GROUND_ANIMATION
#define FULL_SAMPLE_TOPLEVEL_NODE_ANIMATION

#define QUAT_ROT

#define POS_EPSILON 0.0001f
#define ROT_EPSILON 0.0001f
#define SCALE_EPSILON 0.0001f

//#define FLT_EPSILON     1.192092896e-07F        /* smallest such that 1.0+FLT_EPSILON != 1.0 */
//#define FLOAT_EPSILON FLT_EPSILON
#define FLOAT_EPSILON 1e-6f

CHrkNodeAnim::CHrkNodeAnim()
{
	m_pGameNode = NULL;
	m_pGameCont = NULL;

	m_bHavePosAnim = false;
	m_bHaveRotAnim = false;
	m_bHaveScaleAnim = false;
	m_bForceSample = false;

	m_bBipedPosCont = false;
	m_bBipedRotCont = false;
	m_bBipedScaleCont = false;

	m_bFullSample = false;

	for( int i = 0;i<3;i++)
	{
		m_bHavePosKeys[i] = false;
		m_posKeys[i].Resize(0);
	}
	
	for( int i = 0;i<3;i++)
	{
		m_bHaveRotKeys[i] = false;
		m_rotKeys[i].Resize(0);
	}

	for( int i = 0;i<3;i++)
	{
		m_bHaveScaleKeys[i] = false;
		m_scaleKeys[i].Resize(0);
	}

	m_FrameCount = 0;
	m_mtxTab.Resize(0);
}

BOOL CHrkNodeAnim::HaveRotKeys( int index )
{
	return m_bHaveRotKeys[index];
}

BOOL CHrkNodeAnim::HavePosKeys( int index )
{
	return m_bHavePosKeys[index];
}

BOOL CHrkNodeAnim::HaveScaleKeys( int index )
{
	return m_bHaveScaleKeys[index];
}

BOOL CHrkNodeAnim::HaveKeys()
{
	for( int i = 0;i< 3;i++)
	{
		if( m_bHaveRotKeys[i] )
			return TRUE;
		if( m_bHavePosKeys[i] )
			return TRUE;
		if( m_bHaveScaleKeys[i] )
			return TRUE;
	}
	return FALSE;
}

bool CHrkNodeAnim::FullSampleLocalTM( Tab<GMatrix>& mtxTab )
{
	Tab<GMatrix > mtxTab1;

	for( int i = 0;i<m_FrameCount;i++)
	{
		GMatrix mtx = m_pGameNode->GetLocalTM( m_tpf*i + m_start);
		
		IGameNode* pParent = m_pGameNode->GetNodeParent();

		GMatrix mtxx;
		GMatrix m1 = m_pGameNode->GetWorldTM( m_tpf*i + m_start);
		
		if( pParent )
		{
			GMatrix m2 = pParent->GetWorldTM( m_tpf*i + m_start);
			mtxx = m1*m2.Inverse();		
		}
		else
		{
			mtxx = m1;	
		}

		mtxTab1.Append(1,&mtxx );

		//GMatrix mtx3 = m_pGameNode->GetLocalTM( m_tpf*i );
		//GMatrix mtx4 = m_pGameNode->GetWorldTM( m_tpf*i );
		//GMatrix mtx5 = m_pGameNode->GetObjectTM( m_tpf*i );

		mtxTab.Append(1,&mtx);
	}

	return true;
}

bool CHrkNodeAnim::FullSampleKeys(IGameControl* pControl,IGameKeyTab &sample, int frameRate, IGameControlType Type, bool Relative)
{
	bool r = pControl->GetFullSampledKeys(sample,frameRate,Type,Relative);

	IGameKeyTab keyTab;
	bool r1 =  pControl->GetTCBKeys(keyTab,Type);

	int nKeys = sample.Count();
	if( nKeys >0 )
	{	
		TimeValue t = sample[0].t;
		if( sample[0].t > 0 )
		{
			for( int i = 0;i<nKeys;i++ )
				sample[i].t -= t;
		}	
	}

	return r;
}

BOOL CHrkNodeAnim::UnSamplePosKeys( const IGameKeyTab& sampKeys,IGameKeyTab& unSampKeys,int index )
{
	int nKeys = sampKeys.Count();

	if( m_bFullSample )
	{
		if( nKeys < 2 )
			return FALSE;

		for( int i = 0;i<nKeys;i++ )
		{
			float fval = NULL;
			
			fval = sampKeys[i].sampleKey.pval[index];

			IGameKey key;
			key.t = sampKeys[i].t;
			key.flags = sampKeys[i].flags;
			key.linearKey.fval = fval;
			
			unSampKeys.Append( 1,&key );
		}

		return TRUE;
	}

	std::vector<float> d_vec;

	bool bFullSampled = false;

#ifdef FULL_SAMPLE_TOPLEVEL_NODE_ANIMATION
	if( CHrkExport::m_pInstance->m_myScene.IsTopLevelNode(m_pGameNode))
		bFullSampled = true;
#endif

	for( int i = 0;i<nKeys;i++ )
	{
		if( i > 0 )
		{
			Point3 pval_d = sampKeys[i].sampleKey.pval - sampKeys[i-1].sampleKey.pval;
			
			float d = 0.f;
			
			if( index == 0 )
				d = pval_d.x;
			else if( index == 1 )
				d = pval_d.y;
			else if( index == 2 )
				d = pval_d.z;
			
			d_vec.push_back( d );
		}
	}

	for( int i = 0;i<nKeys;i++ )
	{
		float fval = NULL;
			
		fval = sampKeys[i].sampleKey.pval[index];
		
		bool bAppend = false;
		
		if( i == 0 || i == nKeys-1)
		{
			bAppend = true;
		}
		else
		{
			float d1 =  d_vec[i-1];
			float d2 =  d_vec[i];
			
			float dd = abs( d2 - d1 );
			
			if( bFullSampled )	
			{
				bAppend = true;
			}
			else
			{
				if( dd >= POS_EPSILON )
				{
					bAppend = true;
				}
			}	
		}

#if 0
		if( abs(fval) < POS_EPSILON )
		{
			fval = 0.f;
		}
#endif	

		if(bAppend)
		{
			IGameKey key;
			key.t = sampKeys[i].t;
			key.flags = sampKeys[i].flags;
			key.linearKey.fval = fval;
			
			unSampKeys.Append( 1,&key );
		}
	}

	if( bFullSampled );
		return TRUE;

	int nSampKeys = unSampKeys.Count();

	if( nSampKeys < 2 )
	{
		return FALSE;
	}
	else 
	{
		float fval = 0.f;
		BOOL bFind = FALSE;
	
		for( int i = 0;i<nSampKeys;i++)
		{	
			fval = unSampKeys[i].linearKey.fval;
			
			if( abs(fval) >= POS_EPSILON )
			{
				bFind = TRUE;
				break;
			}
		}

		if( !bFind )
		{
			return FALSE;
		}
	
	}
	
	return TRUE;
	
}

BOOL CHrkNodeAnim::UnSampleRotKeys( const IGameKeyTab& sampKeys,IGameKeyTab& unSampKeys,int index  )
{
	int nKeys = sampKeys.Count();

	if( m_bFullSample )
	{
		if( nKeys < 2 )
			return FALSE;

		for( int i = 0;i<nKeys;i++ )
		{
			Quat q = sampKeys[i].sampleKey.qval;

			float fval = q.w;

			IGameKey key;
			key.t = sampKeys[i].t;
			key.flags = sampKeys[i].flags;
			
			key.linearKey.fval = fval;
			key.linearKey.pval = Point3( q.x,q.y,q.z );
			
			unSampKeys.Append( 1,&key );
		}

		return TRUE;
	}


	std::vector<Quat> d_vec;

	for( int i = 0;i<nKeys;i++ )
	{
		if( i > 0 )
		{
			Quat q2 = sampKeys[i].sampleKey.qval;
			Quat q1 = sampKeys[i-1].sampleKey.qval;
			
			Quat q = q2 - q1;		
						
			d_vec.push_back( q );
		}
	}

	for( int i = 0;i<nKeys;i++ )
	{
		Quat q = sampKeys[i].sampleKey.qval;

		bool bAppend = false;

		float fval = q.w;
		
		if( i == 0 || i == nKeys-1)
		{
			bAppend = true;
		}
		else
		{
			float dw =  d_vec[i].w - d_vec[i-1].w ;
			
			float dx = d_vec[i].x - d_vec[i-1].x ;
			float dy = d_vec[i].y - d_vec[i-1].y ;
			float dz = d_vec[i].z - d_vec[i-1].z ;

			dw = abs( dw );
			
			dx = abs( dx );
			dy = abs( dy );
			dz = abs( dz );
	
			if( dx > FLOAT_EPSILON || dy > FLOAT_EPSILON || dz > FLOAT_EPSILON )
			{
				bAppend = true;
			}
			
			if( dw >= ROT_EPSILON )
			{
				bAppend = true;
			}
				
		}
#if 0
		if( abs(fval) < ROT_EPSILON )
		{
			fval = 0.f;
		}
#endif
		if( bAppend )
		{
			IGameKey key;
			key.t = sampKeys[i].t;
			key.flags = sampKeys[i].flags;
			
			key.linearKey.fval = fval;
			key.linearKey.pval = Point3( q.x,q.y,q.z );
			
			unSampKeys.Append( 1,&key );
		}
	}

	int nSampKeys = unSampKeys.Count();

	if( nSampKeys < 2 )
	{
		return FALSE;
	}
	else 
	{
		
		BOOL bFind = FALSE;
		
		for( int i = 0;i<nSampKeys;i++)
		{
			float fw = unSampKeys[i].linearKey.fval;
			float fx =  unSampKeys[i].linearKey.pval[0] ;
			float fy =  unSampKeys[i].linearKey.pval[1];
			float fz =  unSampKeys[i].linearKey.pval[2];

			fw = abs( fw );
			
			fx = abs( fx );
			fy = abs( fy );
			fz = abs( fz );

			if( fx > FLOAT_EPSILON || fy > FLOAT_EPSILON || fz > FLOAT_EPSILON )
			{
				bFind = TRUE;
				break;
			}

			
			if( fw >= ROT_EPSILON )
			{
				bFind = TRUE;
				break;
			}
		}

		if( !bFind )
		{
			return FALSE;
		}
	
	}

	return TRUE;
}
BOOL CHrkNodeAnim::UnSampleScaleKeys( const IGameKeyTab& sampKeys,IGameKeyTab& unSampKeys,int index  )
{
	int nKeys = sampKeys.Count();

	if( m_bFullSample )
	{
		if( nKeys < 2 )
			return FALSE;

		for( int i = 0;i<nKeys;i++ )
		{
			float fval = sampKeys[i].sampleKey.sval.s[index];

			IGameKey key;
			key.t = sampKeys[i].t;
			key.flags = sampKeys[i].flags;
			key.linearKey.fval = fval;
			
			unSampKeys.Append( 1,&key );
		}

		return TRUE;
	}


	std::vector<float> d_vec;

	for( int i = 0;i<nKeys;i++ )
	{
		if( i > 0 )
		{
			Point3 p2 = sampKeys[i].sampleKey.sval.s;	
			Point3 p1 = sampKeys[i-1].sampleKey.sval.s;	
			
			Point3 pval_d = p2 - p1;
			
			float d = 0.f;
			
			if( index == 0 )
				d = pval_d.x;
			else if( index == 1 )
				d = pval_d.y;
			else if( index == 2 )
				d = pval_d.z;
			
			d_vec.push_back( d );
		}
	}

	for( int i = 0;i<nKeys;i++ )
	{
		float fval = sampKeys[i].sampleKey.sval.s[index];
		
		bool bAppend = false;
		
		if( i == 0 || i == nKeys-1)
		{
			bAppend = true;
		}
		else
		{
			float d1 =  d_vec[i-1];
			float d2 =  d_vec[i];
			
			float dd = abs( d2 - d1 );
			
			if( dd >= SCALE_EPSILON)
			{
				bAppend = true;
			}
			
		}
#if 0
		if( abs(fval) < SCALE_EPSILON )
		{
			fval = 0.f;
		}
#endif
		if(bAppend)
		{
			IGameKey key;
			key.t = sampKeys[i].t;
			key.flags = sampKeys[i].flags;
			key.linearKey.fval = fval;
			
			unSampKeys.Append( 1,&key );
		}
	}

	int nSampKeys = unSampKeys.Count();

	if( nSampKeys < 2 )
	{
		return FALSE;
	}
	else 
	{
		BOOL bFind = FALSE;
		
		for( int i = 0;i<nSampKeys;i++)
		{
			float fval = unSampKeys[i].linearKey.fval;
			if( abs(fval) >= SCALE_EPSILON )
			{
				bFind = TRUE;
				break;
			}
		}

		if( !bFind )
		{
			return FALSE;
		}
	
	}

	return TRUE;
}

void CHrkNodeAnim::CollectPosAnim( IGameControl* pControl )
{	
	bool bSampleKeys = 0;

	if(m_bBipedPosCont)
	{
		bSampleKeys = true;
	}
	else
	{
		bSampleKeys = true;
	}

	if( bSampleKeys )
	{
		IGameKeyTab sampKeys;

		FullSampleKeys( pControl,sampKeys,1,IGAME_POS );

		if( m_bForceSample )
		{
			if(sampKeys.Count() == 0)
			{
				sampKeys.SetCount( m_FrameCount );
			}
		}

		for( int i = 0;i<m_FrameCount;i++)
		{
			Point3 p = m_mtxTab[i].Translation();
			Quat q = m_mtxTab[i].Rotation();
			Point3 s = m_mtxTab[i].Scaling();

			sampKeys[i].sampleKey.pval = p;
			
			if( m_bForceSample )
			{
				sampKeys[i].t = m_tpf * i;
			}

		}

		m_bHavePosKeys[0] = UnSamplePosKeys( sampKeys,m_posKeys[0] ,0);
		m_bHavePosKeys[1] = UnSamplePosKeys( sampKeys,m_posKeys[1] ,1);
		m_bHavePosKeys[2] = UnSamplePosKeys( sampKeys,m_posKeys[2] ,2);
		
		m_bLinearPos = TRUE;
	}
	else
	{
		m_bHavePosKeys[0] = pControl->GetBezierKeys( m_posKeys[0],IGAME_POS_X );
		m_bHavePosKeys[1] = pControl->GetBezierKeys( m_posKeys[1],IGAME_POS_Y );
		m_bHavePosKeys[2] = pControl->GetBezierKeys( m_posKeys[2],IGAME_POS_Z );

		m_bLinearPos = FALSE;
	}
}

void CHrkNodeAnim::CollectRotAnim( IGameControl* pControl )
{
	bool bSampleKeys = 0;

	if(m_bBipedRotCont)
	{
		bSampleKeys = true;

	}
	else
	{
		bSampleKeys = true;
	}

	if( bSampleKeys )
	{
		IGameKeyTab sampKeys;
		
		FullSampleKeys( pControl,sampKeys,1,IGAME_ROT );

		for( int i = 0;i<m_FrameCount;i++)
		{
			Point3 p = m_mtxTab[i].Translation();
			Quat q = m_mtxTab[i].Rotation();
			Point3 s = m_mtxTab[i].Scaling();

			sampKeys[i].sampleKey.qval = q;

			m_quatTab.push_back( q );
			
			AngAxis aa;
			aa.Set(q);
			m_angAxisTab.push_back(aa);
		}
	
		m_bHaveRotKeys[0] = UnSampleRotKeys( sampKeys,m_rotKeys[0] ,0 );
		
		m_bLinearRot = TRUE;
	}
	else
	{
		m_bHaveRotKeys[0] = pControl->GetBezierKeys( m_rotKeys[0],IGAME_EULER_X );
		m_bHaveRotKeys[1] = pControl->GetBezierKeys( m_rotKeys[1],IGAME_EULER_Y );
		m_bHaveRotKeys[2] = pControl->GetBezierKeys( m_rotKeys[2],IGAME_EULER_Z );

		m_bLinearRot= FALSE;
	}
}
void CHrkNodeAnim::CollectScaleAnim( IGameControl* pControl )
{
	bool bSampleKeys = 0;

	if(m_bBipedScaleCont)
	{
		bSampleKeys = true;
	}
	else
	{
		bSampleKeys = true;	
	}

	if( bSampleKeys )
	{
		IGameKeyTab sampKeys;
		
		FullSampleKeys( pControl,sampKeys,1,IGAME_SCALE );

		for( int i = 0;i<m_FrameCount;i++)
		{
			Point3 p = m_mtxTab[i].Translation();
			Quat q = m_mtxTab[i].Rotation();
			Point3 s = m_mtxTab[i].Scaling();

			sampKeys[i].sampleKey.sval.s = s;
		}

		
		m_bHaveScaleKeys[0] = UnSampleScaleKeys( sampKeys,m_scaleKeys[0] ,0);
		m_bHaveScaleKeys[1] = UnSampleScaleKeys( sampKeys,m_scaleKeys[1] ,1);
		m_bHaveScaleKeys[2] = UnSampleScaleKeys( sampKeys,m_scaleKeys[2] ,2);
		

		m_bLinearScale = TRUE;
	}
	else
	{
		//extract to fval

		IGameKeyTab bezKeys; 
		BOOL r = pControl->GetBezierKeys( bezKeys,IGAME_SCALE );
		
		if(r)
		{
			int nKeys = bezKeys.Count();
			
			for(int i = 0;i<nKeys;i++)
			{
				IGameKey key;

				for( int j = 0;j<3;j++)
				{
			
					key.t = bezKeys[i].t;
					key.flags = bezKeys[i].flags;
					key.bezierKey.fintan = bezKeys[i].bezierKey.pintan[j];
					key.bezierKey.fouttan = bezKeys[i].bezierKey.pouttan[j];
					key.bezierKey.finLength = bezKeys[i].bezierKey.pinLength[j];
					key.bezierKey.foutLength = bezKeys[i].bezierKey.poutLength[j];
					key.bezierKey.fval = bezKeys[i].bezierKey.sval.s[j];

					m_scaleKeys[j].Append(1,&key);
				}

			}
		}

		m_bLinearScale = FALSE;
	}
	
}

void CHrkNodeAnim::CollectNodeAnim( IGameNode* pNode )
{
	m_pGameNode = pNode;

	TCHAR* name = pNode->GetName();

	if( _tcscmp( name,_T("Ground") )== 0)
	{
		printf("");
	}

	if( _tcscmp( name,_T("W_Bone_Frame") )== 0)
	{
		printf("");
	}

	m_name = name;

	m_tpf = GetTicksPerFrame();

	Interval interval = GetCOREInterface()->GetAnimRange();

	TimeValue start = interval.Start();
	TimeValue end = interval.End();

	m_start = start;

	int nFrameCount = ( end - start ) / m_tpf + 1;

	m_FrameCount = nFrameCount;	
	
	IGameObject * obj = pNode->GetIGameObject();
	
	//obj->InitializeData();
	
	IGameControl* pGameControl = pNode->GetIGameControl();

	m_pGameCont = pGameControl;
	
	FullSampleLocalTM( m_mtxTab );	

	IGameObject::ObjectTypes type = obj->GetIGameType();
	IGameObject::MaxType max_type = obj->GetMaxType();

	m_bBipedPosCont = false;
	m_bBipedRotCont = false;
	m_bBipedScaleCont = false;

	m_bHavePosAnim = false;
	m_bHaveRotAnim = false;
	m_bHaveScaleAnim = false;
	m_bForceSample = false;

	if( pGameControl)
	{
		if (pGameControl->IsAnimated(IGAME_POS))
		{
			m_bHavePosAnim = true;

			IGameControl::MaxControlType maxType = pGameControl->GetControlType( IGAME_POS ); 
			if( maxType == IGameControl::IGAME_BIPED )
			{
				m_bBipedPosCont = true;
			}

			CollectPosAnim( pGameControl );
		}
		else
		{
#ifdef FORCE_EXPORT_TOPLEVEL_NODE_ANIMATION
			if( CHrkExport::m_pInstance->m_myScene.IsTopLevelNode( pNode ) ){
				m_bHavePosAnim = true;
				m_bBipedPosCont = true;
				m_bForceSample = true;
				CollectPosAnim( pGameControl );
			}
#else
	#ifdef FORCE_EXPORT_BIP01_ANIMATION
				if( _tcscmp( name,"Bip01") == 0 )
				{
					m_bHavePosAnim = true;
					m_bBipedPosCont = true;
					m_bForceSample = true;
					CollectPosAnim( pGameControl );
				}
	#endif
	#ifdef FORCE_EXPORT_BIP01_ANIMATION
				if( _tcscmp( name,"Ground") == 0 )
				{
					m_bHavePosAnim = true;
					m_bBipedPosCont = true;
					m_bForceSample = true;
					CollectPosAnim( pGameControl );
				}
	#endif
#endif
		
		}

		if (pGameControl->IsAnimated(IGAME_ROT))
		{
			m_bHaveRotAnim = true;

			IGameControl::MaxControlType maxType = pGameControl->GetControlType( IGAME_ROT ); 
			
			if( maxType == IGameControl::IGAME_BIPED )
			{
				m_bBipedRotCont = true;
			}
			else if( maxType == IGameControl::IGAME_EULER )
			{
				
			}
			
			CollectRotAnim( pGameControl );

		}

		if (pGameControl->IsAnimated(IGAME_SCALE))
		{
			m_bHaveScaleAnim = true;

			if( pGameControl->GetControlType( IGAME_SCALE ) == IGameControl::IGAME_BIPED )
			{
				m_bBipedScaleCont = true;
			}

			CollectScaleAnim( pGameControl );
		}
	}
}

void CHrkNodeAnim::ProcessNodeAffine( CHrkStream& os,CHrkStream& log)
{
	os.PrintTabLine("<affine_tab>");
	os.IncTab();

	int kc = m_apTab.Count();
	for( int i = 0;i<kc;i++ )
	{		
		
		os.PrintTabLine( "<affine t = \"%f,%f,%f\" "
			"q = \"%f,%f,%f,%f\" "
			"f =\"%f\" "
			"k = \"%f,%f,%f\" "
			"u = \"%f,%f,%f,%f\" />",

			m_apTab[i].t.x,
			m_apTab[i].t.y,
			m_apTab[i].t.z,

			m_apTab[i].q.x,
			m_apTab[i].q.y,
			m_apTab[i].q.z,
			m_apTab[i].q.w,
			
			m_apTab[i].f,
			
			m_apTab[i].k.x,
			m_apTab[i].k.y,
			m_apTab[i].k.z,
			m_apTab[i].u.x,
			m_apTab[i].u.y,
			m_apTab[i].u.z,
			m_apTab[i].u.w
		);
	}

	os.DecTab();
	os.PrintTabLine("</affine_tab>");
}

void CHrkNodeAnim::ProcessNodeAnim( CHrkStream& os,CHrkStream& log)
{
	TSTR s = m_pGameNode->GetName();

	GetCOREInterface()->ProgressUpdate(100.f,FALSE,s);

	ProcessPosAnim( os,log );

	ProcessRotAnim( os,log );
	
	ProcessScaleAnim( os,log );

}

void CHrkNodeAnim::ProcessPosAnim( CHrkStream& os,CHrkStream& log)
{
	if( !m_bHavePosAnim)
	{
		return;
	}

	TCHAR* s[3] = {"x","y","z"};

	for( int i = 0;i<3;i++)
	{
		if( m_bHavePosKeys[i] )
		{
			int kc = m_posKeys[i].Count();

			os.PrintTabLine( "<key_tab count = \"%d\" type = \"pos_%s\" mode = \"%s\">",kc,s[i],m_bLinearPos?"linear":"spline"); 
			
			os.IncTab();

			for( int j = 0;j<kc;j++ )
			{
				float fval = 0.f;
				int keyIndex = m_posKeys[i][j].t/m_tpf;
			
				if(m_bLinearPos)
				{
					IGameLinearKey& linKey = m_posKeys[i][j].linearKey;

					fval = linKey.fval;
				}
				else
				{
					IGameBezierKey& bezKey = m_posKeys[i][j].bezierKey;
							
					fval = bezKey.fval;
					
					float ftan1 = bezKey.fintan;
					float ftan2 = bezKey.fouttan;
					float flen1 = bezKey.finLength;
					float flen2 = bezKey.foutLength;
				}

				os.PrintTabLine( "%d;%f;",keyIndex,fval );
			}

			os.DecTab();
			os.PrintTabLine("</key_tab>");
		}

	}

}

void __QuatToEuler( const Quat& q,float& rx,float& ry,float& rz);

void CHrkNodeAnim::ProcessRotAnim( CHrkStream& os,CHrkStream& log)
{

	if( m_bHaveRotKeys[0])
	{
	
		int kc = m_rotKeys[0].Count();

		os.PrintTabLine( "<key_tab count = \"%d\" type = \"rot_q\" mode = \"%s\">",kc,m_bLinearRot?"linear":"spline"); 
		
		os.IncTab();

		float x,y,z,w;

		for( int j = 0;j<kc;j++ )
		{
			float fval = 0.f;

			TimeValue t = m_rotKeys[0][j].t;
			
			int keyIndex = t/m_tpf;

			if(m_bLinearRot)
			{
				IGameLinearKey& linKey = m_rotKeys[0][j].linearKey;
				
				w = linKey.fval;
				x = linKey.pval.x;
				y = linKey.pval.y;
				z = linKey.pval.z;

			}
			else
			{
				
			}


			Quat q,q1;
			float fx,fy,fz;
			float fx1,fy1,fz1;

			float rad[3];		
			q.w = w;
			q.x = x;
			q.y = y;
			q.z = z;

			QuatToEuler(q,rad,EULERTYPE_XYZ);

			fx = rad[0];fy = rad[1];fz = rad[2];

			__QuatToEuler( q,fx1,fy1,fz1 );

			float dx,dy,dz;

			dx = abs( fx1 - fx );
			dy = abs( fy1 - fy );
			dz = abs( fz1 - fz );
			
			if( dx > 1e-2  || dy>1e-2 || dz >1e-2)
			{
				printf("");
			}


			os.PrintTabLine( "%d;%f,%f,%f,%f,%f,%f,%f,%f,%f,%f;",keyIndex,x,y,z,w,fx,fy,fz,fx1,fy1,fz1 );

		}

		os.DecTab();
		os.PrintTabLine("</key_tab>");

	}
}

void CHrkNodeAnim::ProcessScaleAnim( CHrkStream& os,CHrkStream& log)
{
	if( !m_bHaveScaleAnim)
	{
		return ;
	}

	TCHAR* s[3] = {"x","y","z"};

	for( int i = 0;i<3;i++)
	{
		if( m_bHaveScaleKeys[i] )
		{
			int kc = m_scaleKeys[i].Count();
			
			os.PrintTabLine( "<key_tab count = \"%d\" type = \"scale_%s\" mode = \"%s\">",kc,s[i],m_bLinearScale?"linear":"spline"); 
					
			os.IncTab();

			for( int j = 0;j<kc;j++ )
			{
				float fval = 0.f;
				int keyIndex = m_scaleKeys[i][j].t/m_tpf;

				if(m_bLinearScale)
				{
					IGameLinearKey& linKey = m_scaleKeys[i][j].linearKey;
					
					fval = linKey.fval;
	
				}
				else
				{
					IGameBezierKey& bezKey = m_scaleKeys[i][j].bezierKey;
				
					fval = bezKey.fval;
					
					float ftan1 = bezKey.fintan;
					float ftan2 = bezKey.fouttan;
					float flen1 = bezKey.finLength;
					float flen2 = bezKey.foutLength;
				}

				os.PrintTabLine( "%d;%f;",keyIndex,fval );
			}	

			os.DecTab();
			os.PrintTabLine("</key_tab>");
		}

	}	
}